#ifndef WWCOMMON_UTILITY_H
#define WWCOMMON_UTILITY_H

#include "../Core/CommonUtility.hpp"

#include <vector>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include <stdlib.h>
#include <string>
#include <errno.h>
#include <openssl/md5.h>
#include <openssl/des.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <unistd.h>
#include <fcntl.h>

using std::string;
using std::wstring;

using core::StrA2W;
using core::StrW2A;

#define GBK_CODE_PAGE "GBK"
namespace wwcommon
{

using core::utility;

class CommonUtility
{
public:
    static void ToUpper( std::string& src, bool toupper = true)
    {
        if(toupper)
        {
            for(size_t i = 0; i < src.size(); i++)
            {
                if(src[i] >= 'a' && src[i] <= 'z')
                {
                    src[i] = src[i] + 'A' - 'a';
                }
            }
        }
        else
        {
            for(size_t i = 0; i < src.size(); i++)
            {
                if( src[i] >= 'A' && src[i] <= 'Z')
                {
                    src[i] = src[i] + 'a' - 'A';
                }
            }
        }
    }
    // side = 1 trim left, side = 2 trim right, side = 3 trim both side.
    template<typename T> static void TrimStr(T& src, int side, const T& trimstr)
    {
        if( side & 1)
        {
            while(src.size() > 0)
            {
                if(src.find(trimstr) == 0)
                {
                    src = src.substr(trimstr.size());
                }
                else
                {
                    break;
                }
            }
        }
        if( side & 2)
        {
            while(src.size() > 0)
            {
                if(src.substr(src.size() - trimstr.size()) == trimstr)
                {
                    src = src.substr(0, src.size() - trimstr.size());
                }
                else
                {
                    break;
                }
            }
        }
    }
    static void TrimStr(std::string& src, int side, const std::string& trimstr = " ")
    {
        TrimStr<std::string>(src, side, trimstr);
    }

    static void TrimStr(std::wstring& src, int side, const std::wstring& trimstr = L" ")
    {
        TrimStr<std::wstring>(src, side, trimstr);
    }

    static std::string GenerateGuidStr();
    // the base64 impletion of atl not work for mac osx, we need rewrite use openssl
    static void Base64Encode(const unsigned char* in, int inLen, char* out, int& outLen);
    static void Base64Decode(const char* in, int inLen, unsigned char* out, int& outLen);

};// end of class utility

class Md5Hash
{
public:
    static std::string GetMD5(const std::string& src);
    static std::wstring GetMD5WStr(const std::string& src)
    {
        return StrA2W(GetMD5(src));
    }
    static std::string GetMD5FromFile(const std::string& filepath);
    static std::string ConvertMD5ToPrintable(const std::string& src);
};

class BinFile
{
public:
    int m_fd;
    BinFile()
    {
        m_fd = -1;
    }
    bool Open(const std::string& filepath, int flag);
    bool CopyTo(const std::string& dest_filepath);
    bool Write(const void* buffer, size_t len);
    int Read(void* buffer, size_t len);
    off_t GetLength();
    void Close();
    ~BinFile()
    {
        Close();
    }
};
// 旺旺的des在mac下有问题，这里用openssl重写一个
class CDesEncryptMacCompatible
{
public:
//mode == 0: standard Data Encryption Algorithm
//mode == 1: DEA without initial and final permutations for speed
//mode == 2: DEA without permutations and with 128-byte key (completely
//          independent subkeys for each round)
    CDesEncryptMacCompatible(int mode = 0)
        :m_mode(mode)
    {
    }
    std::string SetKey(const std::string& key);
    std::string En_De_crypt(const std::string& data, int env);
    std::string Encrypt(const std::string& data)
    {
        return En_De_crypt(data, DES_ENCRYPT);
    }

    std::string Decrypt(const std::string& data)
    {
        return En_De_crypt(data, DES_DECRYPT);
    }

    bool En_De_CryptFile(const std::string& infilepath, const std::string& outfilepath, int env);
    bool EncryptFile(const std::string& infilepath, const std::string& outfilepath)
    {
        return En_De_CryptFile(infilepath, outfilepath, DES_ENCRYPT);
    }
    bool DecryptFile(const std::string& infilepath, const std::string& outfilepath)
    {
        return En_De_CryptFile(infilepath, outfilepath, DES_DECRYPT);
    }
private:
    int m_mode;
    DES_cblock m_key;
};

class FileUtility
{
public:
    static bool IsPathExist(const std::string& path)
    {
        return ( access(path.c_str(), F_OK) == 0 );
    }
    static std::string MakeWWProfileRoot()
    {
        std::string rootdir = getenv("HOME") + std::string("/.AliIM");
        if( access(rootdir.c_str(), F_OK) != 0 )
        {
            mkdir(rootdir.c_str(), S_IRWXU);
        }
        return rootdir;
    }
    static std::string MakeWWPicSavePath()
    {
        std::string picpath = MakeWWProfileRoot() + "/images";
        if(!IsPathExist(picpath))
        {
            mkdir(picpath.c_str(), S_IRWXU);
        }
        return picpath;
    }
    static std::string MakeWWProfileForUser(const std::string& uid)
    {
        std::string userpath = MakeWWProfileRoot() + "/" + uid;
        if(access(userpath.c_str(), F_OK) != 0)
        {
            mkdir(userpath.c_str(), S_IRWXU);
        }
        return userpath;
    }
    static std::string MakeWWConfigPath(const std::string& uid)
    {
        std::string configpath = MakeWWProfileForUser(uid) + "/configs";
        if(access(configpath.c_str(), F_OK) != 0)
        {
            mkdir(configpath.c_str(), S_IRWXU);
        }
        return configpath;
    }
    static std::string GetWWGlobalCfgPath()
    {
        return utility::GetModulePath() + "/global_config";
    }
};

}

#endif
